﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Bule.Malbilden.Domain;

namespace Bule.Malbilden.Configuration
{
    public class XmlRdaConfigurationReader : IRdaConfigurationReader
    {
        private const string RECOMMENDATION_TAG_NAME = "recommendation";
        private const string GENDER_ATTRIBUTE_NAME = "gender";
        private const string LOWEST_AGE_ATTRIBUTE_NAME = "lowest_age";
        private const string HIGHEST_AGE_ATTRIBUTE_NAME = "highest_age";
        private const string IS_NURSING_ATTRIBUTE_NAME = "is_nursing";
        private const string IS_PREGNANT_ATTRIBUTE_NAME = "is_pregnant";

        XDocument config;

        public XmlRdaConfigurationReader(string path)
        {
            this.config = XDocument.Load(path);
        }

        public XmlRdaConfigurationReader(XDocument configuration)
        {
            this.config = configuration;
        }

        public NutritionData GetRecommendation(Person person)
        {
            XElement foundRecommendation = null;

            if (person.IsPregnant)
                foundRecommendation = GetRecommendationBySingleAttributeValue(IS_PREGNANT_ATTRIBUTE_NAME, "true");
            else if (person.IsNursing)
                foundRecommendation = GetRecommendationBySingleAttributeValue(IS_NURSING_ATTRIBUTE_NAME, "true");
            else
                foundRecommendation = GetRecommendationByAgeAndGender(person);

            return ToNutritionData(foundRecommendation);
        }

        private XElement GetRecommendationBySingleAttributeValue(string attributeName, string value)
        {
            XElement foundElement = null;
            XAttribute attribute;
            var recommendations = config.Root.Descendants(RECOMMENDATION_TAG_NAME);

            foreach (var element in recommendations)
            {
                attribute = element.Attribute(attributeName);
                if (attribute != null && attribute.Value == value)
                {
                    foundElement = element;
                    break;
                }
            }

            return foundElement;
        }

        private XElement GetRecommendationByAgeAndGender(Person person)
        {
            XElement foundRecommendation = null;
            var recommendations = config.Root.Descendants(RECOMMENDATION_TAG_NAME);

            string genderToFind = "male";
            if (person.IsFemale)
                genderToFind = "female";

            foreach (var recommendation in recommendations)
            {
                XAttribute gender = recommendation.Attribute(GENDER_ATTRIBUTE_NAME);
                XAttribute lowest_age = recommendation.Attribute(LOWEST_AGE_ATTRIBUTE_NAME);
                XAttribute highest_age = recommendation.Attribute(HIGHEST_AGE_ATTRIBUTE_NAME);

                if (gender != null && gender.Value == genderToFind &&
                    lowest_age != null && person.Age >= Convert.ToInt32(lowest_age.Value))
                {
                    if (highest_age == null || person.Age <= Convert.ToInt32(highest_age.Value))
                        foundRecommendation = recommendation;
                }
            }

            return foundRecommendation;
        }

        private NutritionData ToNutritionData(XElement element)
        {
            if (element == null)
                return new NutritionData();

            return new NutritionData(0, 0, 0, 0, 0, 0,
                GetValue(element, "VITAMIN_A"),
                GetValue(element, "VITAMIN_B1"),
                GetValue(element, "VITAMIN_B2"),
                GetValue(element, "VITAMIN_B3"),
                GetValue(element, "VITAMIN_B6"),
                GetValue(element, "VITAMIN_B12"),
                GetValue(element, "VITAMIN_C"),
                GetValue(element, "VITAMIN_D"),
                GetValue(element, "VITAMIN_E"),
                GetValue(element, "FOLIC_ACID"),
                GetValue(element, "CALCIUM"),
                GetValue(element, "IRON"),
                GetValue(element, "SODIUM"),
                GetValue(element, "POTASSIUM"),
                GetValue(element, "PHOSPHORUS"),
                GetValue(element, "MAGNESIUM"),
                GetValue(element, "ZINC"),
                GetValue(element, "SELENIUM"));
        }

        private double GetValue(XElement element, string childName)
        {
            var child = element.Element(childName);
            double value = Convert.ToDouble(child.Value,
                System.Globalization.CultureInfo.InvariantCulture);

            return value;
        }
    }
}
